import sqlalchemy as model
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
import os
import shutil

Model = declarative_base()
engine = model.create_engine('sqlite:///sqlite3.db', echo=False, encoding='utf-8')
Session = sessionmaker(bind=engine)
session = Session()


def init(root):
    if not os.path.isdir(root):
        print 'There is no root directory! We will try to make it in your project.'
        os.mkdir(root)
    else:
        print 'All files in your root directory will be removed.'
        shutil.rmtree(root)
        os.mkdir(root)
    Model.metadata.drop_all(engine)
    Model.metadata.create_all(engine)
    session.add(Dir(name=root))
    session.commit()


def get_all_path(dirs_id):
    dir = session.query(Dir).get(dirs_id)
    if not dir.parent_id:
        return dir.name
    else:
        return get_all_path(dir.parent_id) + '/' + dir.name


class User(Model):
    __tablename__ = 'users'

    id = model.Column(model.Integer, primary_key=True)
    name = model.Column(model.String(20), unique=True, nullable=False)
    password = model.Column(model.String(128), nullable=False)
    is_admin = model.Column(model.Boolean, default=False)
    info = model.Column(model.String(50))
    sets = relationship("Set", cascade="all, delete, delete-orphan", back_populates='user')
    dir_id = model.Column(model.ForeignKey('dirs.id'), nullable=False)
    dir = relationship("Dir", back_populates='users', cascade="all, delete")
    pers = relationship("Per", cascade="all, delete, delete-orphan")

    def get_dict(self):
        arr = []
        for each in self.sets:
            arr.append(each.get_dict())
        arr1 = []
        for each in self.pers:
            arr1.append(each.get_dict())
        return {
            "id": self.id,
            "name": self.name,
            "password": self.password,
            "is_admin": self.is_admin,
            "info": self.info,
            "sets": arr,
            "pers": arr1,
        }

    def __repr__(self):
        return str(self.id)


class Set(Model):
    __tablename__ = 'sets'

    id = model.Column(model.Integer, primary_key=True)
    name = model.Column(model.String(50), unique=True, nullable=False)
    info = model.Column(model.String(50))
    # many(this) -> one
    user_id = model.Column(model.ForeignKey('users.id'), nullable=False)
    dir_id = model.Column(model.ForeignKey('dirs.id'), nullable=False)
    user = relationship("User", back_populates='sets')
    dir = relationship("Dir", back_populates='sets', cascade="all, delete")
    # many -> many
    pers = relationship("Per", cascade="all, delete, delete-orphan")

    def get_dict(self):
        arr = []
        for each in self.pers:
            arr.append(each.get_dict())

        return {
            'id': self.id,
            'name': self.name,
            'user_id': self.user_id,
            'pers': arr,
            'info': self.info,
            'path': get_all_path(self.dir_id)
        }

    def __repr__(self):
        return str(self.id)


class Per(Model):
    __tablename__ = 'pers'
    id = model.Column(model.Integer, primary_key=True)
    user_id = model.Column(model.Integer, model.ForeignKey('users.id'), nullable=False)
    set_id = model.Column(model.Integer, model.ForeignKey('sets.id'), nullable=False)
    write = model.Column(model.Boolean, default=False, nullable=False)

    def get_dict(self):
        return {
            'user_id': self.user_id,
            'set_id': self.set_id,
            'write': self.write,
        }


class Dir(Model):
    __tablename__ = 'dirs'

    id = model.Column(model.Integer, primary_key=True)
    name = model.Column(model.String(50), unique=True, nullable=False)
    parent_id = model.Column(model.ForeignKey('dirs.id'), default=None)

    users = relationship("User", cascade="all, delete, delete-orphan", back_populates='dir')
    sets = relationship("Set", cascade="all, delete, delete-orphan", back_populates='dir')

    def get_dict(self):
        arr1 = []
        arr2 = []
        for each in self.docs:
            arr1.append(each.get_dict())
        for each in self.children:
            arr2.append(each.get_dict())
        return {
            'id': self.id,
            'name': self.name,
            'parent_id': self.parent_id,
        }

    def __repr__(self):
        return str(self.id)
